package my.test.csdn.weixin_43767015.basic.ch12.transaction.declarative.annotation.propagation.nested.eachcall.service;

import java.util.Random;

import javax.annotation.Resource;

import org.springframework.aop.framework.AopContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

@Component
public class TxNestedEachService {
    /**
     * jdbc模版，用于操作数据库
     */
    @Resource
    private JdbcTemplate jdbcTemplate;
    
    /** 在开启了事务的方法m1中调用m2 */
    /**
	         内层事务操作失败时只是自身回到到保存点的位置,不会引起外层事务的回滚,
	         而外层事务因失败而回滚时，内层事务所做的所有动作也会回滚。
     */
	@Transactional(propagation = Propagation.REQUIRED)
    public void m1() {
		//m1 do something1
        String sql = "insert into tx_study (name,age) values (?,?)";
        jdbcTemplate.update(sql, "TxRequired_m1_something1", 30);     
        try {
			TxNestedEachService o =(TxNestedEachService)AopContext.currentProxy();
			o.m2();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        //m1 do something2
        jdbcTemplate.update(sql, "TxRequired_m1_something2", 30);
        //抛出一个RuntimeException
        //throw new RuntimeException();
	}
	
	@Transactional(propagation = Propagation.NESTED)
	public void m2() {
        String sql = "insert into tx_study (name,age) values (?,?)";
        jdbcTemplate.update(sql, "TxNested_m2", 30);   
        //抛出一个RuntimeException
        //throw new RuntimeException();
	}
	
	/**
    	仅仅会创建一个物理级别的事务，内部嵌套子事务以SavePoint保存点的方法记录，这是真正的嵌套事务，“内部”事务受到“外部”事物的影响
	 */
	@Resource
	private DataSourceTransactionManager transactionManager;

	public DataSourceTransactionManager getTransactionManager() {
		return transactionManager;
	}
	
	public void tran() {
	    //获得一个事务管理器
	    DataSourceTransactionManager txManager = getTransactionManager();
    	//创建一个事务定义对象，可以设置事务的属性
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        //只能以编程方式执行时才能显式设置事务名称
        def.setName("SomeTxName");
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        //m1开启一个新事务ts1
        TransactionStatus ts1 = txManager.getTransaction(def);
        try {
        	//m1 do something1
            String sql = "insert into tx_study (name,age) values (?,?)";
            jdbcTemplate.update(sql, "TxRequired_m1_something1", 30);     
        	
            //m2开启一个新事务ts2
            //实际上就是在当前事务中创建一个保存点而已
            Object savepoint = ts1.createSavepoint();
        	
            try {
                //执行m2方法业务逻辑
                m2();
            } catch (Throwable ex) {
                //回滚ts2事务，这里仅仅是对保存点的操作
                ts1.rollbackToSavepoint(savepoint);
            }
            //m1 do something2
            jdbcTemplate.update(sql, "TxRequired_m1_something2", 30);
            //抛出一个RuntimeException
            Random random = new Random();
            int i = random.nextInt(2);
            if(i == 1) {
            	throw new RuntimeException();
            }                    
        }catch (Throwable throwable) {
            //回滚ts1事务
            txManager.rollback(ts1);
            throw throwable;
        }
        //提交ts1事务
        txManager.commit(ts1);
	}
}
